﻿//#define TESTING

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using System.Xml.XPath;
using System.Diagnostics;
using Microsoft.Win32;
using System.Drawing.Text;

namespace ClockIn
{
    public partial class Form1 : Form
    {
        private FormAbout m_FormAbout = new FormAbout();

        private System.Windows.Forms.NotifyIcon notifyIcon1;
        private System.Windows.Forms.ContextMenu contextMenu1;
        private System.Windows.Forms.MenuItem menuItem1;

        //private DataTable m_DataTable = new DataTable();

        public Form1()
        {
            InitializeComponent();

            //dataGridView1.AutoGenerateColumns = false;
            //m_DataTable.Columns.Add("Date");
            //m_DataTable.Columns.Add("Description", typeof(String));
            //dataGridView1.DataSource = m_DataTable;

            this.DoubleBuffered = true;

            SystemEvents.SessionSwitch += new SessionSwitchEventHandler(SystemEvents_SessionSwitch);
            SystemEvents.PowerModeChanged += new PowerModeChangedEventHandler(SystemEvents_PowerModeChanged);

            m_Timer.Tick += new EventHandler(m_Timer_Tick);

            this.components = new System.ComponentModel.Container();
            this.contextMenu1 = new System.Windows.Forms.ContextMenu();
            this.menuItem1 = new System.Windows.Forms.MenuItem();

            // Initialize contextMenu1
            this.contextMenu1.MenuItems.AddRange(
                        new System.Windows.Forms.MenuItem[] { this.menuItem1 });

            // Initialize menuItem1
            this.menuItem1.Index = 0;
            this.menuItem1.Text = "E&xit";
            this.menuItem1.Click += new System.EventHandler(this.menuItem1_Click);

            notifyIcon1 = new NotifyIcon();

            // The Icon property sets the icon that will appear
            // in the systray for this application.
            notifyIcon1.Icon = this.Icon;

            // The ContextMenu property sets the menu that will
            // appear when the systray icon is right clicked.
            notifyIcon1.ContextMenu = this.contextMenu1;

            // The Text property sets the text that will be displayed,
            // in a tooltip, when the mouse hovers over the systray icon.
            notifyIcon1.Text = "Clock In";
            notifyIcon1.Visible = true;

            // Handle the Click event to activate the form.
            //notifyIcon1.Click += new EventHandler(notifyIcon1_Click);
            notifyIcon1.MouseClick += new MouseEventHandler(notifyIcon1_MouseClick);
        }

        System.Windows.Forms.Timer m_Timer = new Timer();
        DateTime m_StartTime;
        private void Form1_Load(object sender, EventArgs e)
        {
            LoadSettings();

#if TESTING
            AddTestingData();
#else
            LoadEvents();

            // Add App Start Event
            EventItem NewEvent = new EventItem(DateTime.Now, EventType.AppStart);
            AddEvent(NewEvent);
            SetStartTime(NewEvent.EventTime);
#endif

            // when will the seconds and milliseconds match?
            //DateTime now = DateTime.Now;
            //int msToFirstEvent = 

            
            //m_Timer.Interval = 60000; // once a minute
            //m_Timer.Start();

            
            //Properties.Settings.Default.LastStart = m_StartTime;
            //Properties.Settings.Default.LastStop = DateTime.Now;
            //Properties.Settings.Default.Save();
        }

        void SetFont()
        {
            // 1: ?
            // 2: News Gothic

            InstalledFontCollection installedFontCollection = new InstalledFontCollection();
            // Get the array of FontFamily objects.
            FontFamily[] fontFamilies = installedFontCollection.Families;
            //fontFamilies[0].Name

            //label1.Font = new Font(
        }

        void AddTestingData()
        {
            {
                DateTime temp = new DateTime(2012, 10, 4, 9, 35, 14);
                EventItem NewEvent = new EventItem(temp, EventType.AppStart);
                AddEvent(NewEvent);
            }

            {
                DateTime temp = new DateTime(2012, 10, 4, 9, 38, 31);
                EventItem NewEvent = new EventItem(temp, EventType.AppClosed);
                AddEvent(NewEvent);
            }

            {
                DateTime temp = new DateTime(2012, 10, 4, 9, 42, 40);
                EventItem NewEvent = new EventItem(temp, EventType.AppStart);
                AddEvent(NewEvent);
            }

            {
                DateTime temp = new DateTime(2012, 10, 4, 12, 13, 52);
                EventItem NewEvent = new EventItem(temp, EventType.SessionLocked);
                AddEvent(NewEvent);
            }

            {
                DateTime temp = new DateTime(2012, 10, 4, 12, 24, 15);
                EventItem NewEvent = new EventItem(temp, EventType.SessionUnlocked);
                AddEvent(NewEvent);
            }

            {
                DateTime temp = new DateTime(2012, 10, 4, 15, 45, 34);
                EventItem NewEvent = new EventItem(temp, EventType.Suspended);
                AddEvent(NewEvent);
            }

            {
                DateTime temp = new DateTime(2012, 10, 4, 15, 58, 12);
                EventItem NewEvent = new EventItem(temp, EventType.Resumed);
                AddEvent(NewEvent);
            }

            {
                DateTime temp = new DateTime(2012, 10, 4, 17, 54, 46);
                EventItem NewEvent = new EventItem(temp, EventType.SessionLocked);
                AddEvent(NewEvent);
            }

            {
                DateTime temp = new DateTime(2012, 10, 6, 8, 12, 32);
                EventItem NewEvent = new EventItem(temp, EventType.SessionUnlocked);
                //ListViewItem tempItem = AddEvent(NewEvent);
                //listView1.SelectedItems.Clear();
                //tempItem.Selected = true;

                DataGridViewRow tempRow = AddEvent(NewEvent);
                tempRow.Selected = true;
            }

            {
                DateTime temp = new DateTime(2012, 10, 6, 9, 14, 58);
                EventItem NewEvent = new EventItem(temp, EventType.SessionLocked);
                AddEvent(NewEvent);
            }

            {
                DateTime temp = new DateTime(2012, 10, 6, 9, 17, 13);
                EventItem NewEvent = new EventItem(temp, EventType.SessionUnlocked);
                AddEvent(NewEvent);
            }
        }

        void SetStartTime(DateTime StartTime)
        {
            m_Timer.Stop();
            m_StartTime = StartTime;
            label1.Text = m_StartTime.ToString(@"hh:mm tt");
            label3.Text = m_StartTime.ToString(@"D");
            UpdateElapsedTime(m_StartTime, DateTime.Now);

            // when will the seconds and milliseconds match?
            //DateTime now = DateTime.Now;
            //StartTime.Second

            DateTime now = DateTime.Now;
            TimeSpan TempTimeSpan = now - StartTime;
            int seconds = 60 - TempTimeSpan.Seconds; // seconds to next minute
            int milliseconds = 1000 - TempTimeSpan.Milliseconds; // milliseconds to next second

            m_Timer.Interval = (seconds * 1000) + milliseconds; // once a minute
            m_Timer.Start();
        }

        Color m_Color1 = Color.White;
        Color m_Color2 = Color.Beige; //Color.FromArgb(0xfc, 0xfd, 0xef); //Color.Beige; // fcfdef
        Color m_Color2Selected = Color.FromArgb(0x00, 0x75, 0xf8);
        DataGridViewRow AddEvent(EventItem Event)
        {
            string strDateTime = Event.EventTime.ToString(@"g");

            string Description = string.Empty;
            switch (Event.EventType)
            {
                case EventType.AppStart:
                    Description = "App Started";
                    break;
                case EventType.AppClosed:
                    Description = "App Closed";
                    break;
                case EventType.SessionLocked:
                    Description = "Session Locked";
                    break;
                case EventType.SessionUnlocked:
                    Description = "Session Unlocked";
                    break;
                case EventType.Suspended:
                    Description = "Session Suspended (Sleep)";
                    break;
                case EventType.Resumed:
                    Description = "Session Resumed (Wake)";
                    break;
                case EventType.Custom:
                    Description = Event.EventDescription;
                    break;
                default:
                    Debug.Assert(false, "Unexpected EventType");
                    break;
            }

            int index = 0;
            while (index < dataGridView1.Rows.Count)
            {
                EventItem tag = dataGridView1.Rows[index].Tag as EventItem;
                if (Event.EventTime >= tag.EventTime)
                {
                    break;
                }
                index++;
            }

            dataGridView1.Rows.Insert(index, 1);
            DataGridViewRow Row = dataGridView1.Rows[index];
            Row.Cells[ColumnDateTime.Index].Value = strDateTime;
            Row.Cells[ColumnEventDescription.Index].Value = Description;
            Row.Tag = Event;

            dataGridView1.CurrentCell = dataGridView1.Rows[index].Cells[0];

            if (dataGridView1.Rows.Count > 1)
            {
                DataGridViewRow PreviousRow = dataGridView1.Rows[1];
                EventItem PreviousEventItem = GetEventItem(PreviousRow);
                if (PreviousEventItem.EventTime.Date != Event.EventTime.Date)
                {
                    Color newColor = (PreviousRow.DefaultCellStyle.BackColor == m_Color1 ? m_Color2 : m_Color1);

                    if (newColor == m_Color2)
                    {
                        Row.DefaultCellStyle.SelectionBackColor = m_Color2Selected;
                    }

                    Row.DefaultCellStyle.BackColor = newColor;
                }
                else
                {
                    Row.DefaultCellStyle.BackColor = PreviousRow.DefaultCellStyle.BackColor;
                    Row.DefaultCellStyle.SelectionBackColor = PreviousRow.DefaultCellStyle.SelectionBackColor;
                }
            }
            else
            {
                Row.DefaultCellStyle.BackColor = m_Color1;
            }

            return Row;
        }

        void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e)
        {
            EventType Type = EventType.Undefined;
            switch (e.Mode)
            {
                case PowerModes.Suspend:
                    Type = EventType.Suspended;
                    break;
                case PowerModes.Resume:
                    Type = EventType.Resumed;
                    break;
            }

            if (Type != EventType.Undefined)
            {
                EventItem NewEvent = new EventItem(DateTime.Now, Type);
                AddEvent(NewEvent);
            }
        }

        void SystemEvents_SessionSwitch(object sender, SessionSwitchEventArgs e)
        {
            EventType Type = EventType.Undefined;
            switch (e.Reason)
            {
                case SessionSwitchReason.SessionLock:
                    Type = EventType.SessionLocked;
                    break;
                case SessionSwitchReason.SessionUnlock:
                    Type = EventType.SessionUnlocked;
                    break;
            }

            if (Type != EventType.Undefined)
            {
                EventItem NewEvent = new EventItem(DateTime.Now, Type);
                AddEvent(NewEvent);
            }
        }

        void m_Timer_Tick(object sender, EventArgs e)
        {
            m_Timer.Interval = 60000;

            UpdateElapsedTime(m_StartTime, DateTime.Now);
            Properties.Settings.Default.LastStop = DateTime.Now;
            Properties.Settings.Default.Save();
        }

        void UpdateElapsedTime(DateTime StartTime, DateTime EndTime)
        {
            TimeSpan TempTimeSpan = EndTime - StartTime;
            label2.Text = GetElapsedTimeString(TempTimeSpan);
        }

        string GetElapsedTimeString(TimeSpan TimeSpan)
        {
            //TimeSpan.TicksPerDay
            int Hours = (int)Math.Abs(Math.Truncate(TimeSpan.TotalHours));
            //int Hours = Math.Abs((TimeSpan.Days * 24) + TimeSpan.Hours);
            int Minutes = Math.Abs(TimeSpan.Minutes);

            string HourString = "Hour";
            if (Hours != 1)
            {
                HourString += "s";
            }

            string MinuteString = "Minute";
            if (Minutes != 1)
            {
                MinuteString += "s";
            }

            string ReturnString =
                Hours + " " + HourString + ", " +
                Minutes + " " + MinuteString + "";

            return ReturnString;
        }

        void notifyIcon1_MouseClick(object sender, MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Left)
            {
                // Set the WindowState to normal if the form is minimized.
                if (this.WindowState == FormWindowState.Minimized)
                    this.WindowState = FormWindowState.Normal;

                this.ShowInTaskbar = true;
                Visible = true;
                this.Focus();

                // Activate the form.
                this.Activate();
                label1.Focus();
            }
        }

        private void menuItem1_Click(object Sender, EventArgs e)
        {
            SaveSettings();
            notifyIcon1.Dispose();
            Application.Exit();
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (e.CloseReason == CloseReason.UserClosing)
            {
                this.ShowInTaskbar = false;
                e.Cancel = true;
                this.Hide();
            }
        }

        protected override void OnVisibleChanged(EventArgs e)
        {
            base.OnVisibleChanged(e);

            if (this.Visible)
            {
                // Start the ticker...
                //bool test = true;
            }
            else
            { 
                // Stop the ticker...
                //m_Timer.Stop();
            }
        }

        private void LoadSettings()
        {
            if (!Properties.Settings.Default.FirstRun)
            {
                this.Size = Properties.Settings.Default.FormSize;
                this.Location = Properties.Settings.Default.FormLocation;
            }
        }

        private void LoadEvents()
        {
            if (!Properties.Settings.Default.FirstRun)
            {
                if (Properties.Settings.Default.Log != null)
                {
                    // Load the Log
                    XmlDocument xmlDoc = Properties.Settings.Default.Log;
                    XmlNodeList nodeList = xmlDoc.SelectNodes("/eventItems/eventItem");
                    for (int i = nodeList.Count-1; i >= 0; i--)
                    {
                        EventItem newEvent = new EventItem(nodeList[i]);
                        AddEvent(newEvent);
                    }
                }

                if (Properties.Settings.Default.LastStop != null)
                {
                    EventItem newEvent = new EventItem(Properties.Settings.Default.LastStop, EventType.AppClosed);
                    AddEvent(newEvent);
                }
            }
            
        }

        private void SaveSettings()
        {
            Properties.Settings.Default.FirstRun = false;
            if (this.WindowState == FormWindowState.Normal)
            {
                Properties.Settings.Default.FormSize = this.Size;
                Properties.Settings.Default.FormLocation = this.Location;
            }
            else
            {
                Properties.Settings.Default.FormSize = this.RestoreBounds.Size;
                Properties.Settings.Default.FormLocation = this.RestoreBounds.Location;
            }

            XmlDocument xmlDoc = new XmlDocument();
            XmlNode rootNode = xmlDoc.CreateElement("eventItems");
            xmlDoc.AppendChild(rootNode);
            foreach (DataGridViewRow row in dataGridView1.Rows)
            {
                EventItem eventItem = GetEventItem(row);
                XmlNode node = eventItem.SerializeToXml(xmlDoc, "eventItem");
                rootNode.AppendChild(node);
            }
            Properties.Settings.Default.Log = xmlDoc;

            Properties.Settings.Default.LastStop = DateTime.Now;
            Properties.Settings.Default.Save();
        }

        private EventItem GetEventItem(DataGridViewRow Row)
        {
            object tag = Row.Tag;
            if (tag != null && tag is EventItem)
            {
                EventItem Event = tag as EventItem;
                return Event;
            }

            Debug.Assert(false);
            return null;
        }

        private void dataGridView1_SelectionChanged(object sender, EventArgs e)
        {
            if (dataGridView1.SelectedRows.Count == 1)
            {
                DataGridViewRow Row = dataGridView1.SelectedRows[0];
                if (Row.Tag == null)
                {
                    return;
                }

                EventItem Event = GetEventItem(dataGridView1.SelectedRows[0]);
                SetStartTime(Event.EventTime);
            }
            else if (dataGridView1.SelectedRows.Count > 1)
            {
                m_Timer.Stop();

                // we want first and last selected items...
                EventItem Event2 = GetEventItem(dataGridView1.SelectedRows[0]);
                EventItem Event1 = GetEventItem(dataGridView1.SelectedRows[dataGridView1.SelectedRows.Count - 1]);

                UpdateElapsedTime(Event1.EventTime, Event2.EventTime);
            }
        }

        private void aboutClockInToolStripMenuItem_Click(object sender, EventArgs e)
        {
            m_FormAbout.ShowDialog(this);
        }

        private void dataGridView1_MouseClick(object sender, MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Right)
            {
                DataGridView.HitTestInfo info = dataGridView1.HitTest(e.X, e.Y);
                if (info.RowIndex >= 0)
                {
                    deleteToolStripMenuItem.Text = "Delete Event Entry";
                    if (dataGridView1.SelectedRows.Count > 1)
                    {
                        deleteToolStripMenuItem.Text = "Delete " + dataGridView1.SelectedRows.Count + " Event Entries";
                    }

                    contextMenuStrip1.Show(dataGridView1, e.Location);
                }
            }
        }

        private void exportLogToolStripMenuItem_Click(object sender, EventArgs e)
        {
            saveFileDialog1.ShowDialog();
        }

        private void deleteToolStripMenuItem_Click(object sender, EventArgs e)
        {
            foreach (DataGridViewRow Row in dataGridView1.SelectedRows)
            {
                dataGridView1.Rows.Remove(Row);
            }
        }

        private void toolStripMenuItem1_Click(object sender, EventArgs e)
        {
            FormInsertEvent newForm = new FormInsertEvent();
            if (newForm.ShowDialog(this) == System.Windows.Forms.DialogResult.OK)
            {
                AddEvent(new EventItem(newForm.EventDateTime, newForm.EventDescription));
            }
            newForm.Dispose();
        }
    }

    public enum EventType
    {
        Undefined,
        AppStart,
        AppClosed,
        SessionLocked,
        SessionUnlocked,
        Suspended,
        Resumed,
        Custom
    }

    class EventItem
    {
        public EventItem(DateTime EventTime, String EventDescription)
        {
            m_EventTime = EventTime;
            m_EventType = ClockIn.EventType.Custom;
            m_EventDescription = EventDescription;
        }

        public EventItem(DateTime EventTime, EventType EventType)
        {
            m_EventTime = EventTime;
            m_EventType = EventType;
        }

        public EventItem(XmlNode EventItemXml)
        {
            try
            {
                string strEventTime = EventItemXml.Attributes["eventTime"].Value;
                string strEventType = EventItemXml.Attributes["eventType"].Value;
                XmlAttribute eventDescription = EventItemXml.Attributes["eventDescription"];
                m_EventDescription = (eventDescription != null ? eventDescription.Value : String.Empty);

                m_EventTime = new DateTime(Convert.ToInt64(strEventTime));
                m_EventType = (EventType)Enum.Parse(typeof(EventType), strEventType);
            }
            catch
            {
                Debug.Assert(false, "There was a problem parsing the EventItem XML");
            }
        }

        DateTime m_EventTime;
        public DateTime EventTime
        {
            get { return m_EventTime; }
        }

        EventType m_EventType;
        public EventType EventType
        {
            get { return m_EventType; }
        }

        String m_EventDescription = string.Empty;
        public String EventDescription
        {
            get { return m_EventDescription; }
        }

        public XmlNode SerializeToXml(XmlDocument xmlDoc, string ElementName)
        {
            XmlNode rootNode = xmlDoc.CreateElement(ElementName);

            // EventTime
            {
                XmlAttribute attribute = xmlDoc.CreateAttribute("eventTime");
                attribute.Value = m_EventTime.Ticks.ToString();
                rootNode.Attributes.Append(attribute);
            }

            // EventType
            {
                XmlAttribute attribute = xmlDoc.CreateAttribute("eventType");
                attribute.Value = m_EventType.ToString();
                rootNode.Attributes.Append(attribute);
            }

            if (m_EventType == ClockIn.EventType.Custom)
            {
                // EventDescription
                {
                    XmlAttribute attribute = xmlDoc.CreateAttribute("eventDescription");
                    attribute.Value = m_EventDescription;
                    rootNode.Attributes.Append(attribute);
                }
            }

            return rootNode;
        }
    }
}
